/*
 *  Arrow
 *
 *  Created by David Giovannini on 1/5/07.
 *  Copyright 2007 Software by Jove. All rights reserved.
 *
 */
 
#ifndef SBJ_Arrow_Message_h
#define SBJ_Arrow_Message_h

#include "SBJ/Container/Node.h"
#include "SBJ/Arrow/Topic.h"
#include "SBJ/Interfaces/IExceptionObserver.h"

#include <string>

namespace SBJ
{

namespace Arrow
{

/*
Class: Arrow::Message


*/

class Message : public Node< Message >
{
public:
	typedef Arrow::Topic Topic;

	typedef size_t Priority;
	static const Priority highest_priority;
	static const Priority lowest_priority;
	static const Priority unknown_priority;

	enum EDropped
	{
		dropped_InvalidTopic,
		dropped_PriorityTooLow,
		dropped_FellOffQueue,
		dropped_NoSubscribers,
		dropped_VisitationCanceled,
		dropped_UncaughtException
	};

	// Subclasses may create a type attribute
	// of the same name for type safety
	typedef void Subscriber;
	enum { fully_independent = false };
		
	/// Helper method
	template < typename MsgType >
	static MsgType* duplicate( MsgType& msg )
	{
		if ( msg.getTopic().isValid() )
			return static_cast< MsgType* >( msg.getTopic().getMsgProxy().duplicate( msg ) );
		return 0;
	}
	/// Use this constructor for basic message creation.
	inline Message( const Topic& topic, Priority priority = highest_priority );
	
	/// Subclasses overload this constructor in terms of the subclass.
	inline Message( const Message& rhs );

	/// Destructor
	virtual ~Message( void );

	void operator delete( void* p );
	
	/// Returns the associated Topic
	inline const Topic& getTopic( void ) const;

	/// Returns the associated priority
	inline Priority getPriority( void ) const;
	
// Overridables

	/// Returns true if message may enter the queue
	inline bool isValid( void ) const;

	/// Returns true if this message supports consume
	inline bool doesConsume( const Message& rhs ) const;
	
	/// Subclasses overload this method in terms of the subclass
	// This implementation throws std::logic_err
	inline void consume( Message& rhs );
	
	/// Returns the number of subscribers required to make
	/// dispatching multithreaded
	virtual size_t getThreadedThreshold( void ) const;
	
	/// If threaded, do we block until all dispatching is complete
	virtual bool doesBlockOnDispatch( void ) const;
	
	/// Will be called once on dispatch if Topic is not empty
	virtual bool beginInvocations( size_t count );
	
	/// Will be called on dispatch for each subscriber if beginInvocations returns true 
	// Subclasses overload this method in terms of its Subscriber attribute.
	inline void invoke( Subscriber* );
	
	// One of the following methods will be called by the channel
	// to complete the journey of the message.

	/// Will be called once on dispatch if beginInvocations returns true
	virtual void endInvocations( void );

	/// Will be called on dispatch if Topic is empty
	virtual void execute( void );

	/// Will be called if message fails to be fulfilled.
	virtual void dropped( EDropped reason );
	
private:
	Topic m_topic;
	Priority m_priority;

	// Not implemented
	Message& operator = ( Message& );
};
/*
class MessageTraits
{
public:
	void	Subscriber;
	void	Param;
}

template < typename MessageTraits >
class MessageT : public Message
{
public:
	typedef SubscriberT Subscriber;

	MessageT( const Topic& topic, const Param& param, Priority priority = highest_priority )
	: Message( topic, priority )
	, m_param( param )
	{
	}

	inline void invoke( Subscriber* subscriber )
	{
		subscriber->Function( m_param );
	}

private:
	
};
*/
}

}

#include "SBJ/Arrow/Message.inl"

#endif